#include "../mq_comm/mq_helper.hpp"
#include "../mq_comm/mq_log.hpp"
#include "../mq_comm/mq_msg.pb.h"
#include <iostream>
#include <unordered_map>
#include <mutex>
#include <memory>
namespace mq
{

    using namespace ns_helper;
    using namespace Ns_Log;

    struct MsgQueue
    {
        using ptr = std::shared_ptr<MsgQueue>;
        std::string name;
        bool durable;
        bool exclusive;
        bool auto_delete;

        google::protobuf::Map<std::string, std::string> args;
        MsgQueue() {}
        MsgQueue(const std::string &qname,
                 bool qdurbale,
                 bool qexclusive,
                 bool qauto_delete,
                 const google::protobuf::Map<std::string, std::string> &qargs): name(qname), durable(qdurbale),
                                                                        exclusive(qexclusive),
                                                                        auto_delete(qauto_delete), args(qargs)

        {
        }
        void setArgs(const std::string str_args) // 将字符串风格的args转换填充到args中
        {
            std::vector<std::string> sub_args;
            SplitHelper::split(str_args, "&", sub_args);

            for (auto &str : sub_args)
            {
                size_t pos = str.find("=");
                std::string key = str.substr(0, pos);
                std::string val = str.substr(pos + 1);
                args[key] = val;
            }
        }
        std::string getArgs() // 将args中的数据序列化为一个字符串, 并返回
        {
            std::string res;
            for (auto &pair : args)
            {
                res += pair.first + "=" + pair.second + "&";
            }
            return res;
        }
    };
    // 队列持久化类管理
    using QueueMap = std::unordered_map<std::string, MsgQueue::ptr>;
    class MsqQueueMapper
    {
    public:
        MsqQueueMapper(const std::string &dbfile) : _sql_helper(dbfile)
        {
            std::string path = FileHelper::parentDirectory(dbfile);
            FileHelper::createDirectory(path);
            assert(_sql_helper.open()); // 数据库打开不成功直接终止程序
            CreateTable();
        }
        void CreateTable()
        {
            std::string cre_sql = "create table if not exists queue_table";
            cre_sql += "(name varchar(32) primary key, durable int, exclusive int,";
            cre_sql += "auto_delete int, args varchar(255));";

            assert(_sql_helper.exec(cre_sql, nullptr, nullptr));
        }
        void RemoveTable()
        {
            std::string del_sql = "drop table if exists queue_table;";
            bool ret = _sql_helper.exec(del_sql, nullptr, nullptr);
            if (!ret)
            {
                LOG(ERROR) << "消息队列数据表删除失败 ! ! !\n";
                abort(); // 直接异常退出程序
            }
        }
        bool insert(MsgQueue::ptr mq_p)
        {
            // bool类型直接插入int类型字段的表中会进行类型转换: 0, 1;
            std::stringstream ss;
            ss << "insert into queue_table values(";
            ss << "'" << mq_p->name << "',";
            ss << mq_p->durable << ",";
            ss << mq_p->exclusive << ",";
            ss << mq_p->auto_delete << ",";
            ss << "'" << mq_p->getArgs() << "');";
            return _sql_helper.exec(ss.str(), nullptr, nullptr);
        }
        void Remove(const std::string &name)
        {
            std::stringstream ss;
            ss << "delete from queue_table where name=";
            ss << "'" << name << "';";
            _sql_helper.exec(ss.str(), nullptr, nullptr);
        }

        QueueMap Recovery()
        {
            std::unordered_map<std::string, MsgQueue::ptr> res;
            std::string sql = "select * from queue_table;";
            _sql_helper.exec(sql, selectCallback, &res);
            return res;
        }

    private:
        static int selectCallback(void *arg, int col, char **row, char **fields)
        {
            QueueMap *result = (QueueMap *)arg;
            auto mqp = std::make_shared<MsgQueue>();
            mqp->name = row[0];
            mqp->durable = (bool)std::stoi(row[1]);
            mqp->exclusive = (bool)std::stoi(row[2]);
            mqp->auto_delete = (bool)std::stoi(row[3]);
            if (row[4])
                mqp->setArgs(row[4]);
            result->insert(std::make_pair(mqp->name, mqp));
            return 0; // 不能少(表示正常退出)
        }

    private:
        SqliteHelper _sql_helper;
    };
    class MsgQueueManager
    {
    public:
        using ptr = std::shared_ptr<MsgQueueManager>;
        
        MsgQueueManager(const std::string &dbfile) : _mapper(dbfile)
        {
            _queues = _mapper.Recovery();
        }
        bool declareQueue(const std::string &qname,
                          bool qdurbale,
                          bool qexclusive,
                          bool qauto_delete,
                          const google::protobuf::Map<std::string, std::string> &qargs)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            auto it = _queues.find(qname);
            if (it != _queues.end())
            {
                return true;
            }
            auto mqp = std::make_shared<MsgQueue>(qname, qdurbale, qexclusive, qauto_delete, qargs);
            if (qdurbale == true)
            {
                bool ret = _mapper.insert(mqp);
                if (!ret)
                    return false;
            }
            _queues.insert(std::make_pair(qname, mqp));
            return true;
        }
        void deleteQueue(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            auto it = _queues.find(name);
            if (it == _queues.end())
            {
                return;
            }
            if (it->second->durable == true)
                _mapper.Remove(name);
            _queues.erase(name);
        }

        MsgQueue::ptr selectQueue(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            auto it = _queues.find(name);
            if (it == _queues.end())
                return MsgQueue::ptr();
            return it->second;
        }
        QueueMap allQueue()
        {
            // 存在线程安全问题:
            // 不能直接引用返回, 其他线程可能在修改其中的数据
            std::unique_lock<std::mutex> lock(_mtx);
            return _queues;
        }
        bool IsExists(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            auto it = _queues.find(name);
            if (it == _queues.end())
            {
                return false;
            }
            return true;
        }
        size_t Size()
        {
            std::unique_lock<std::mutex> lock(_mtx);
            return _queues.size();
        }
        void Clear()
        {
            std::unique_lock<std::mutex> lock(_mtx);
            _mapper.RemoveTable();
            _queues.clear();
        }

    private:
        std::mutex _mtx;
        MsqQueueMapper _mapper;
        QueueMap _queues;
    };
}
